package com.pvdnc.riru.system_server;

import android.annotation.SuppressLint;
import android.os.IBinder;
import android.util.Log;

import com.pvdnc.riru.common.ServiceObserver;
import com.pvdnc.riru.common.ServiceObserverManager;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import andhook.lib.xposed.XC_MethodHook;
import andhook.lib.xposed.XposedBridge;

@SuppressLint({"PrivateApi","DiscouragedPrivateApi"})
public class HookServiceManager {
    private static final String TAG=HookServiceManager.class.getSimpleName();

    public static final HookServiceManager INSTANCE=new HookServiceManager();

    private HookServiceManager(){

    }

    public void hookAll(){
        new AddService().hook();
    }

    private final Map<String,IBinder> mServiceMap=new ConcurrentHashMap<>();

    public void cacheService(String serviceName,IBinder service){
        mServiceMap.put(serviceName, service);

        ServiceObserverManager.INSTANCE.callObserver(serviceName,service);
    }

    class AddService extends XC_MethodHook {
        public void hook() {
            try {
                Class<?> smClass = Class.forName("android.os.ServiceManager");
                Method method = smClass.getDeclaredMethod("addService", String.class, IBinder.class);
                XposedBridge.hookMethod(method, this);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            String name= (String) param.args[0];
            Log.d(TAG,"attempt to add service:"+name);
        }

        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            String name= (String) param.args[0];
            IBinder service= (IBinder) param.args[1];
            Log.d(TAG,name+" -> "+service);
            cacheService(name,service);
        }
    }
}
